<?php

namespace App\Recharge;


use App\Jobs\ApiRechargeJob;
use App\Models\XnBatchOrder;
use App\Recharge\Service\MerchantCombinationService;
use Throwable;
use Exception;
use GuzzleHttp\TransferStats;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Client\Response;
use App\Recharge\Bean\BasicInformation;
use GuzzleHttp\Promise\PromiseInterface;
use App\Recharge\Bean\RequestResultBean;
use App\Recharge\Interfaces\ApiInterface;
use Illuminate\Http\Client\PendingRequest;
use GuzzleHttp\Exception\ConnectException;
use App\Models\InterfaceConfiguration;
use App\Recharge\Exceptions\SuspensionOfEnforcement;


class Library
{
    /**
     * @param XnBatchOrder $order
     * @return void
     */
    static public function pushApiJob(XnBatchOrder $order): void
    {
        ApiRechargeJob::dispatch($order)->afterCommit()->onQueue('api-recharge-job');
    }

    /**
     * 32位订单号
     *
     * @param int $length
     * @return string
     */
    static public function order_no(int $length = 32): string
    {
        $orderNo = date('YmdHis') .
            substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13)))), 0, 8);
        $residue = max($length - strlen($orderNo), 0);
        for ($i = 0; $i < $residue; $i ++) {
            $orderNo .= mt_rand(0, 9);
        }
        return $orderNo;
    }

    /**
     * @param ApiInterface $api
     * @param PendingRequest $http
     * @param InterfaceConfiguration $config
     * @param BasicInformation $dataBean
     * @param bool $returnPromise
     * @return RequestResultBean|PromiseInterface
     * @throws SuspensionOfEnforcement
     */
    public static function executeRecharge(
        ApiInterface $api,
        PendingRequest $http,
        InterfaceConfiguration $config,
        BasicInformation $dataBean,
        bool $returnPromise = false
    ): PromiseInterface|RequestResultBean {
        // 获取充值
        $promise = $api->recharge($http->async(), $config, $dataBean);
        // 是否返回promise
        if ($returnPromise) {
            return $promise;
        }
        /** @var ConnectException|Response $result **/
        $result = $promise->wait();
        if ($result instanceof ConnectException) {
            throw new SuspensionOfEnforcement('请求连接失败:' . $result->getMessage());
        }
        // 设计一个同步返回的数据方法
        if (method_exists($api, 'synchronous_processing')) {
            return $api->synchronous_processing($config,$dataBean,self::apiRechargeToRequestResultBean($result));
        }
        return self::apiCurrencyRespHandle($config, self::apiRechargeToRequestResultBean($result));
    }

    /**
     * @param Response $response
     * @return RequestResultBean
     */
    static public function apiRechargeToRequestResultBean(Response $response): RequestResultBean
    {
        $result = new RequestResultBean();
        /** @var TransferStats $stats **/
        $stats = $response->transferStats;
        $request = $stats->getRequest();
        $result->setUrl($request->getUri()->__toString());
        $result->setRequest($request->getBody()->__toString());
        $result->setMethod($request->getMethod());
        $result->setResponse($response->body());
        $result->setOptions($stats->getHandlerStats());
        return $result;
    }

    /**
     * 默认的同步接口返回信息处理
     *
     * @param InterfaceConfiguration $config
     * @param RequestResultBean $bean
     * @return RequestResultBean
     */
    static public function apiCurrencyRespHandle(InterfaceConfiguration $config, RequestResultBean $bean): RequestResultBean
    {
        // 默认是通过的
        $result = true;
        // 第三方接口返回的错误信息
        $errMessage = "";

        // 请求返回信息转数组
        $resp = match ($config->api_sync_data_format) {
            "xml"   => xml2array($bean->getResponse()),
            default => json2array($bean->getResponse()),
        };
        $bean->setFormatResponse($resp);
        // 解析json 解析失败的话 就默认成功
        $judge = json2array($config->api_sync_judge);
        if (empty($judge)) {
            goto end;
        }

        foreach ($judge as $k => $v) {
            if (!isset($resp[$k]) || ($resp[$k] != $v)) {
                $result = false;
                break;
            }
        }
        if ($result) {
            goto end;
        }
        // 返回信息
        if ($config->api_sync_err_key != "") {
            $errMessage = data_get($resp, $config->api_sync_err_key, $config->title . '下单失败');
        }

        // 判断并返回
        end:
        return $bean->setResult($result)->setErrorMessage($errMessage);
    }

    /**
     * @param string $phone
     * @return string
     */
    static public function mobilePhoneLocationInquiry(string $phone): string
    {
        try {
            /** @var PhoneHomeLocation $phone **/
            $phone = PhoneHomeLocation::query()->firstOrNew(compact('phone'), ['last_time' => 0]);
            if ($phone->last_time > (time() - 60*60*24*7)) {
                return $phone->company;
            }
            $array = httpClient()
                ->withToken('328c5fe0b22d440ab3aea86bc81f9276', 'APPCODE')
                ->get("https://jisusjhmcx.market.alicloudapi.com/shouji/query", ['shouji' => $phone])
                ->json();
            if (($status = data_get($array, 'status')) !== 0) {
                throw new Exception(data_get($array, 'msg', '返回状态码不为0,=' . $status));
            }
            $result = data_get($array, 'result', []);
            if (empty($result)) {
                throw new Exception("未返回result参数");
            }
            $phone->last_time = time();
            $phone->fill($result)->save();
            // 返回
            return $phone->company;
        } catch (Throwable $e) {
            Log::channel('error')->error('手机号归属地查询失败',[
                'ding'  => true,
                'phone' => $phone,
                'error' => error2array($e),
            ]);
            return "";
        }
    }
}
